#pragma once

#include "VariableManager.hpp"
#include "VariableTypes.hpp"
#include "MathVariableTypes.hpp"
#include "ProgramMain.hpp"
#include <list>


class VariableEditor : public ITwCallbackListener
{
public:
	VariableEditor();
	~VariableEditor();
	void Init(VariableManager *varMan, IParamObject *obj, const string &title = string());
	
	void AddButton(const string &label, TwCallbackContext *ctx);

	virtual void TwSetVar(uint tag, const void *data);
	virtual void TwGetVar(uint tag, void *outData);
	virtual void TwButton(uint tag);

private:
	struct TwCallbackTag
	{
		Variable *m_Var;
		uint m_Index;

		TwCallbackTag() { }
		TwCallbackTag(Variable *var, uint index = 0) : m_Var(var), m_Index(index) { }
	};

	typedef common::shared_ptr<char, common::DeleteArrayPolicy> CharArraySharedPtr;
	typedef std::vector<CharArraySharedPtr> CharArraySharedPtrVector;

	static uint m_NextParamIndex;
	static void GenerateUniqueName(std::string &out);

	VariableManager *m_VarMan;
	IParamObject *m_Obj;
	TwBar *m_Bar;
	string m_BarName;
	CharArraySharedPtrVector m_HelperStrings;
	std::list<TwCallbackContext> m_CallbackContexts; // Not a vector, so elements won't be reallocated.
	std::vector<TwCallbackTag> m_CallbackTags;
	uint m_ButtonCount;

	void CreateBar(const string &title);
	void InitVar(Variable *var);
	void InitUnknownVar(Variable *var);
	void InitCharVar(CharVariable *var);
	void InitBoolVar(BoolVariable *var);
	template <typename T> void InitUintVar(UintVariable<T> *var);
	template <typename T> void InitIntVar(IntVariable<T> *var);
	template <typename T> void InitRealVar(RealVariable<T> *var);
	void InitStlStringVar(StlStringVariable *var);
	void InitFilePathVar(FilePathVariable *var);
	void InitDirPathVar(DirPathVariable *var);
	void InitEnumVar(EnumVariable *var);
	void InitTimeVar(TimeVariable *var);
	void InitVec2Var(Vec2Variable *var);
	void InitVec3Var(Vec3Variable *var);
	void InitVec4Var(Vec4Variable *var);
	void InitColorVar(ColorVariable *var);
	void InitColorfVar(ColorfVariable *var);
	void InitQuaternionVar(QuaternionVariable *var);
	void InitPointVar(PointVariable *var);
	void InitRectVar(RectVariable *var);
	void InitRectfVar(RectfVariable *var);
	void InitBoxVar(BoxVariable *var);
	void InitMatrixVar(MatrixVariable *var);

	void FormatDef(std::string &outName, std::string &outDef, Variable *var);
	template <typename T> void FormatIntegerDef(std::string &outName, std::string &outDef, IntegerVariable<T> *var);
	template <typename T> void FormatRealDef(std::string &outName, std::string &outDef, RealVariable<T> *var);
	template <typename T> void FormatVecComponentDef(std::string &outName, std::string &outDef, VecVariable<T> *var, int componentIndex, const string &groupName, const string &label);
	void FormatIntComponentDef(std::string &outName, std::string &outDef, int componentIndex, const string &groupName, const string &label, int minVal, int maxVal);
	TwCallbackContext * CreateTwCallbackContext(Variable *var, uint index = 0);
};
